package com.xq.tmall.agu.timer;

import com.xq.tmall.agu.ferign.FetchStockSpider;
import com.xq.tmall.entity.Stock;
import com.xq.tmall.service.StockFetchErrorService;
import com.xq.tmall.service.StockService;
import com.xq.tmall.util.DateUtil;
import com.xq.tmall.util.IpFerginUtil;
import com.xq.tmall.util.SpringContextUtil;
import com.xq.tmall.util.TradingDateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Slf4j
public class StockTimer {

    // 批次管理
    private static final int BATCH_SIZE = 300;
    private static final int MAX_RETRIES = 3;
    private static final long RETRY_DELAY = 3000;

    @Autowired
    private StockService stockService;

    @Autowired
    private TradingDateUtil tradingDateUtil;

    @Autowired
    private StockFetchErrorService fetchErrorService;

    @Autowired
    private IpFerginUtil ipFerginUtil;

    @Scheduled(cron = "0 10 10 * * ?")  // 每天10:10执行
    public void scheduled10Task() {
        LocalDateTime dateTime = LocalDateTime.now();
        // 周末不执行
        boolean isWeek = DateUtil.isWeekend(dateTime);
        if(isWeek){
            log.info("周末不执行");
            return;
        }
        ipFerginUtil.setRedisIp();
        processMarket();
    }

    @Scheduled(cron = "0 25 14 * * ?")  // 每天10:10执行
    public void scheduled115Task() {
        LocalDateTime dateTime = LocalDateTime.now();
        // 周末不执行
        boolean isWeek = DateUtil.isWeekend(dateTime);
        if(isWeek){
            log.info("周末不执行");
            return;
        }
        ipFerginUtil.setRedisIp();
        processMarket();
    }

    @Scheduled(cron = "0 10 15 * * ?")  // 每天15:10执行
    public void scheduledTask() {
        LocalDateTime dateTime = LocalDateTime.now();
        // 周末不执行
        boolean isWeek = DateUtil.isWeekend(dateTime);
        if(isWeek){
            log.info("周末不执行");
            return;
        }
     /*   if (!tradingDateUtil.isTradingDay()) {
            log.info("非交易时段，跳过任务");
            return;
        }*/
        ipFerginUtil.setRedisIp();
        processMarket();
    }

    private void processMarket() {
        log.info("开始处理市场");
        try {
            List<Stock> allStocks = getMarketStocks();
            if (allStocks.isEmpty()) {
                log.info("市场无股票数据");
                return;
            }

            log.info("共需处理 {} 只股票，分 {} 批处理",
                    allStocks.size(),
                    (int) Math.ceil((double) allStocks.size() / BATCH_SIZE));

            List<Stock> allResults = new ArrayList<>();

            // 分批处理股票代码
            for (int i = 0; i < allStocks.size(); i += BATCH_SIZE) {
                int end = Math.min(i + BATCH_SIZE, allStocks.size());
                List<Stock> batch = allStocks.subList(i, end);

                log.info("正在处理批次: {}-{}/{}", i, end, allStocks.size());

                List<Stock> batchResults = processStockBatch(
                        batch.stream().map(Stock::getCode).toArray(String[]::new)
                );

                if (!batchResults.isEmpty()) {
                    allResults.addAll(batchResults);
                }

                // 添加批次间隔，避免请求过于频繁
                TimeUnit.MILLISECONDS.sleep(8000);
            }

            if (!allResults.isEmpty()) {
                saveInBatches(allResults, 500);
                log.info("任务完成，共保存 {} 条股票数据", allResults.size());
            } else {
                log.warn("未获取到有效的股票数据");
            }
        }catch (Exception e){
            log.info("抓取异常");
        }
    }

    private List<Stock> processStockBatch(String[] codes) {
        int attempt = 0;
        while (attempt < MAX_RETRIES) {
            try {
                FetchStockSpider spider = new FetchStockSpider(codes);
                List<Stock> results = spider.fetchData();

                if (results != null && !results.isEmpty()) {
                    log.info("批次抓取成功，获取 {} 条数据", results.size());
                    return results;
                }
            } catch (Exception e) {
                log.warn("批次抓取失败 (尝试 {}/{}): {}",
                        attempt + 1, MAX_RETRIES, e.getMessage());
            }

            attempt++;
            try {
                TimeUnit.MILLISECONDS.sleep(RETRY_DELAY * attempt);
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                break;
            }
        }
        try {
            List<String> list = Arrays.stream(codes).collect(Collectors.toList());
            fetchErrorService.batchUpdate(list, "02");
        } catch (Exception e) {
            log.info("插入异常日志信息失败:", e);
        }
        log.error("批次抓取失败，已达到最大重试次数 {}", MAX_RETRIES);
        return Collections.emptyList();
    }


    private List<Stock> getMarketStocks() {
        List<Stock> stockListSz = getStockService().getSZStockCodes();
        List<Stock> stockListSh = getStockService().getSHStockCodes();
        stockListSh.addAll(stockListSz);
        return stockListSh;
    }

    private void saveInBatches(List<Stock> stocks, int batchSize) {
        int total = stocks.size();
        for (int i = 0; i < total; i += batchSize) {
            int end = Math.min(i + batchSize, total);
            List<Stock> batch = stocks.subList(i, end);

            try {
                stockService.batchUpdate(batch);
                log.info("分批保存成功: {}-{}/{}", i, end, total);
            } catch (Exception e) {
                log.error("分批保存失败: {}-{}", i, end, e);
                // 单条保存作为降级方案
                saveOneByOne(batch);
            }
        }
    }

    private void saveOneByOne(List<Stock> stocks) {
        for (Stock stock : stocks) {
            try {
                stockService.updateByPrimaryKeySelective(stock);
            } catch (Exception e) {
                log.error("保存股票失败: {}", stock.getCode(), e);
            }
        }
    }

    private StockService getStockService() {
        if (stockService == null) {
            stockService = SpringContextUtil.getBean(StockService.class);
        }
        return stockService;
    }
}
